
import 'dart:convert';

import 'package:equatable/equatable.dart';

import '../../../data/models/error_model.dart';
import '../../../data/models/sync_operation.dart';
import '../../../data/remote/database_helper.dart';

import 'package:flutter/material.dart';
import '../../../core/utils/show_toast.dart';
import '/core/app_export.dart';
part 'sync_event.dart';
part 'sync_state.dart';



/// A bloc that manages the state of a Login according to the event that is dispatched to it.
class SyncBloc extends Bloc<SyncEvent, SyncState> {

  static SyncBloc get(context) => BlocProvider.of(context);

  SyncBloc(SyncState initialState) : super(initialState) {
    on<SyncInitialEvent>(_fetchAllOperations);
    //on<FetchAllOperationsEvent>(_fetchAllOperations);
    on<FetchPOperationsEvent>(_fetchPendingOperations);
    on<FetchSOperationsEvent>(_fetchSOperations);
    on<FetchFOperationsEvent>(_fetchFOperations);
    on<SyncPendingOperationsEvent>(_syncPendingOperations);
    on<ReSyncOperationEvent>(_onReSyncOperation);
  }

  _onInitialize(
      SyncInitialEvent event,
      Emitter<SyncState> emit,
      ) async {
    emit(state.copyWith());
  }

  _fetchAllOperations(
      SyncInitialEvent event,
      Emitter<SyncState> emit,
      ) async {
    final pOperations = await DatabaseHelper.getPendingOperations();
    final fOperations = await DatabaseHelper.getFailedOperations();
    final sOperations = await DatabaseHelper.getSyncedOperations();

    emit(state.copyWith(
      pending:pOperations.map((e)=>SyncOperation.fromJson(e)).toList() ,
      field:fOperations.map((e)=>SyncOperation.fromJson(e)).toList(),
      success: sOperations.map((e)=>SyncOperation.fromJson(e)).toList(),
    ));
  }

  _fetchPendingOperations(
      FetchPOperationsEvent event,
      Emitter<SyncState> emit,
      ) async {
    final pendingOperations = await DatabaseHelper.getPendingOperations();
    emit(state.copyWith(pending: pendingOperations.map((e)=>SyncOperation.fromJson(e)).toList()));
  }


  _fetchFOperations(
      FetchFOperationsEvent event,
      Emitter<SyncState> emit,
      ) async {
    final fOperations = await DatabaseHelper.getFailedOperations();
    emit(state.copyWith(field: fOperations.map((e)=>SyncOperation.fromJson(e)).toList()));
  }

  _fetchSOperations(
      FetchSOperationsEvent event,
      Emitter<SyncState> emit,
      ) async {
    final sOperations = await DatabaseHelper.getSyncedOperations();
    emit(state.copyWith(success: sOperations.map((e)=>SyncOperation.fromJson(e)).toList()));
  }


  _syncPendingOperations(
      SyncPendingOperationsEvent event,
      Emitter<SyncState> emit,
      ) async {
    final pendingOperations = state.pending;

    for (var operation in pendingOperations) {
      try {
        // قم بتنفيذ طلب الـ API هنا
        emit(state.copyWith(currentLoading: operation.operationId));
        final response = await operation.sendRequest();
        emit(state.copyWith(currentLoading: null));

        var res = ErrorModel.fromResponse(response!);

        if (res.stateCode == 200 && res.state != false) {
          // إذا كانت المزامنة ناجحة، قم بتحديث حالة العملية إلى "synced"
          state.pending.removeWhere((e)=>e.operationId == operation.operationId);
          await DatabaseHelper.updateSyncOperation(
            operation.operationId,
            {'status': 'synced', 'updated_at': DateTime.now().toIso8601String()},
          );
        } else {
          // إذا فشلت المزامنة، قم بتحديث رسالة الخطأ
          await DatabaseHelper.updateSyncOperation(
            operation.operationId,
            {'status': 'failed', 'error_message': res.stacktrace, 'updated_at': DateTime.now().toIso8601String()},
          );
        }
      } catch (error) {
        // في حال حدوث خطأ غير متوقع، قم بتحديث حالة العملية ورسالة الخطأ
        await DatabaseHelper.updateSyncOperation(
          operation.operationId,
          {'status': 'failed', 'error_message': error.toString(), 'updated_at': DateTime.now().toIso8601String()},
        );
      }
    }

    // بعد الانتهاء من المزامنة، قم بجلب العمليات المعلقة مجددًا لتحديث الواجهة
    add(FetchPOperationsEvent());
  }

  _onReSyncOperation(
      ReSyncOperationEvent event,
      Emitter<SyncState> emit,
      )async{
    emit(state.copyWith(currentLoading:event.operation.operationId ));
    final response = await event.operation.sendRequest();
    var res = ErrorModel.fromResponse(response!);

    if (res.stateCode == 200 && res.state != false) {
      // إذا كانت المزامنة ناجحة، قم بتحديث حالة العملية إلى "synced"
      state.pending.removeWhere((e)=>e.operationId == event.operation.operationId);
      state.field.removeWhere((e)=>e.operationId == event.operation.operationId);
      await DatabaseHelper.updateSyncOperation(
        event.operation.operationId,
        {'status': 'synced', 'updated_at': DateTime.now().toIso8601String()},
      );
    } else {
      // إذا فشلت المزامنة، قم بتحديث رسالة الخطأ
      await DatabaseHelper.updateSyncOperation(
        event.operation.operationId,
        {'status': 'failed', 'error_message': res.stacktrace, 'updated_at': DateTime.now().toIso8601String()},
      );
    }
    emit(state.copyWith(currentLoading: null));
  }

}
